#include "Subsystems/BlockBehaviors/SubsystemDoorBlockBehavior.h"
#include "Log.h"
#include "Managers/EntityManager.h"
#include "Managers/GameManager.h"
#include "Managers/BlocksManager.h"
#include "Components/ComponentBlockEntity.h"
#include "Components/ComponentChest.h"
#include "Subsystems/SubsystemTerrain.h"
#include "Blocks/DoorBlock.h"
#include "GameSingleton.h"

#include "Blocks/WoodenDoorBlock.h"
#include "Blocks/IronDoorBlock.h"
#include "Blocks/CellDoorBlock.h"

namespace PocketSurvival
{
    SubsystemDoorBlockBehavior::SubsystemDoorBlockBehavior()
    {
        m_handleBlocks.push_back(WoodenDoorBlock::Index());
        m_handleBlocks.push_back(IronDoorBlock::Index());
        m_handleBlocks.push_back(CellDoorBlock::Index());
    }

    void SubsystemDoorBlockBehavior::onBlockAdded(int32_t value, int32_t oldValue, int32_t x, int32_t y, int32_t z)
    {
        int32_t cellContents = m_terrain->getCellContents(x, y - 1, z);
        int32_t cellContents2 = m_terrain->getCellContents(x, y + 1, z);
        if (GameSingleton::blocksManager->blocks[cellContents]->IsTransparent == false && cellContents2 == 0)
        {
            m_terrain->changeCell(x, y + 1, z, value);
        }
    }
    void SubsystemDoorBlockBehavior::onBlockRemoved(int32_t value, int32_t oldValue, int32_t x, int32_t y, int32_t z)
    {
        if (DoorBlock::IsTopPart(x, y, z))
        {
            m_terrain->changeCell(x, y - 1, z, 0);
        }
        if (DoorBlock::IsBottomPart(x, y, z))
        {
            m_terrain->changeCell(x, y + 1, z, 0);
        }
    }
    bool SubsystemDoorBlockBehavior::onInteract(const TerrainRaycastResult &raycastResult, ComponentMiner *componentMiner)
    {
        // spdlog::info("door onInteract");
        const CellFace &cellFace = raycastResult.cellFace;
        int32_t cellValue = m_terrain->getCellValue(cellFace.point);
        int32_t num = Terrain::ExtractContents(cellValue);
        int32_t data = Terrain::ExtractData(cellValue);
        bool open = DoorBlock::GetOpen(data);
        return openCloseDoor(cellFace.point.posX, cellFace.point.posY, cellFace.point.posZ, !open);

        // 下面是有电路才用的
        // if (num == 56 || !IsDoorElectricallyConnected(cellFace.X, cellFace.Y, cellFace.Z))
        // {
        // 	bool open = DoorBlock.GetOpen(data);
        // 	return OpenCloseDoor(cellFace.X, cellFace.Y, cellFace.Z, !open);
        // }
        // return true;
    }
    void SubsystemDoorBlockBehavior::onNeighborBlockChanged(int32_t x, int32_t y, int32_t z, int32_t neighborX, int32_t neighborY, int32_t neighborZ)
    {
        int32_t cellValue = m_terrain->getCellValue(x, y, z);
        int32_t num = Terrain::ExtractContents(cellValue);
        Block *obj = GameSingleton::blocksManager->blocks[num];
        int32_t data = Terrain::ExtractData(cellValue);
        if (obj->isBlock<DoorBlock *>() == false)
        {
            return;
        }
        if (neighborX == x && neighborY == y && neighborZ == z)
        {
            if (DoorBlock::IsBottomPart(x, y, z))
            {
                int32_t value = Terrain::ReplaceData(m_terrain->getCellValue(x, y + 1, z), data);
                m_terrain->changeCell(x, y + 1, z, value);
            }
            if (DoorBlock::IsTopPart(x, y, z))
            {
                int32_t value2 = Terrain::ReplaceData(m_terrain->getCellValue(x, y - 1, z), data);
                m_terrain->changeCell(x, y - 1, z, value2);
            }
        }
        if (DoorBlock::IsBottomPart(x, y, z))
        {
            int32_t cellContents = m_terrain->getCellContents(x, y - 1, z);
            if (GameSingleton::blocksManager->blocks[cellContents]->IsTransparent)
            {
                m_terrain->destroyCell(0, x, y, z, 0, false);
            }
        }
        if (false == DoorBlock::IsBottomPart(x, y, z) && false == DoorBlock::IsTopPart(x, y, z))
        {
            m_terrain->destroyCell(0, x, y, z, 0, false);
        }
    }

    bool SubsystemDoorBlockBehavior::openCloseDoor(int32_t x, int32_t y, int32_t z, bool open)
    {
        int32_t cellValue = m_terrain->getCellValue(x, y, z);
        int32_t num = Terrain::ExtractContents(cellValue);
        if (GameSingleton::blocksManager->blocks[num]->isBlock<DoorBlock *>() == true)
        {
            int32_t data = DoorBlock::SetOpen(Terrain::ExtractData(cellValue), open);
            int32_t value = Terrain::ReplaceData(cellValue, data);
            m_terrain->changeCell(x, y, z, value);
            return true;
        }
        return false;
    }

    static const std::string subsystemName = "DoorBlockBehavior";
    const std::string &SubsystemDoorBlockBehavior::getName() const
    {
        return subsystemName;
    }
    void SubsystemDoorBlockBehavior::update(float dt)
    {
    }
    void SubsystemDoorBlockBehavior::load(const nlohmann::json &json)
    {
        m_terrain = GameSingleton::singletonPtr->getSingleton<SubsystemTerrain>();
    }
    void SubsystemDoorBlockBehavior::save(nlohmann::json &json)
    {
    }
    void SubsystemDoorBlockBehavior::saveToMsgJson(nlohmann::json &jsonData)
    {
    }
}